<?php
class Database
{
    const FETCH_ASSOC   = 0x01;
    const FETCH_NUM     = 0x02;
    const FETCH_BOTH    = 0x03;

    /**
     * @var mysql
     */
    protected $_driver;

	public function __construct()
	{
	}

    public function setConnection($driverName, $host, $username, $password, $dbname)
    {
        $this->_driver = $this->_loadDriver($driverName);

        $this->_driver->connect($host, $username, $password, $dbname);
    }

	public function escape($data)
	{
		return $this->_driver->escape($data);
	}

    public function quoteLike($data)
    {
        return "'" . $this->escape($data) . "'";
    }

	public function query($query, $bind = array())
	{
        $bind = $this->_cleanBind($bind);

        // Bind data to mark symbols
        $query = str_replace('%', '.+', $query);
        $query = str_replace('?', '%s', $query);
        $query = vsprintf($query, $bind);
        $query = str_replace('.+', '%', $query);

        $result = $this->_driver->query($query);

     /*   var_dump($query);
        exit();*/

        if ($result)
        {
            return $result;
        }

        throw new QueryErrorException($query);
	}

    public function fetchAll($query, $bind = array())
    {
        return $this->_driver->fetch($this->query($query, $bind));
    }

	public function fetchRow($query, $bind = array())
	{
		$rows = $this->_driver->fetch($this->query($query, $bind));

		if (isset($rows[0]))
		{
			return $rows[0];
		}

		return false;
	}

	public function fetchOne($query, $bind = array())
	{
		$row = $this->_driver->fetch($this->query($query, $bind), self::FETCH_NUM);

        if (isset($row[0][0]))
        {
            return $row[0][0];
        }

        return false;
	}

    public function fetchAllKeyed($query, $key, $bind = array())
    {
        $rows = $this->fetchAll($query, $bind);

        $i = -1;
        $result = array();
        foreach ($rows as &$row)
        {
            $i++;
            $result[isset($row[$key])? $row[$key] : $i] = $row;
        }

        return $result;
    }

    public function getInsertId()
    {
        return $this->_driver->getInsertId();
    }

    public function limitQueryResults($query, $limit, $offset = 0)
    {
        if ($limit > 0)
        {
            $query .= " LIMIT $offset, $limit";
        }

        return $query;
    }

    public function getConditionsForClause(array $sqlConditions)
    {
        if ($sqlConditions)
        {
            return '(' . implode(') AND (', $sqlConditions) . ')';
        }
        else
        {
            return '1=1';
        }
    }

    public function getOrderByClause(array $choices, array $fetchOptions, $defaultOrderSql = '')
    {
        $orderSql = null;

        if (!empty($fetchOptions['order']) && isset($choices[$fetchOptions['order']]))
        {
            $orderSql = $choices[$fetchOptions['order']];

            if (empty($fetchOptions['direction']))
            {
                $fetchOptions['direction'] = 'asc';
            }

            $dir = (strtolower($fetchOptions['direction']) == 'desc' ? 'DESC' : 'ASC');
            $orderSqlOld = $orderSql;
            $orderSql = sprintf($orderSql, $dir);
            if ($orderSql === $orderSqlOld)
            {
                $orderSql .= ' ' . $dir;
            }
        }

        if (!$orderSql)
        {
            $orderSql = $defaultOrderSql;
        }
        return ($orderSql ? 'ORDER BY ' . $orderSql : '');
    }

    public function prepareLimitFetchOptions(array $fetchOptions)
    {
        $limitOptions = array('limit' => 0, 'offset' => 0);
        if (isset($fetchOptions['limit']))
        {
            $limitOptions['limit'] = intval($fetchOptions['limit']);
        }
        if (isset($fetchOptions['offset']))
        {
            $limitOptions['offset'] = intval($fetchOptions['offset']);
        }

        if (isset($fetchOptions['perPage']) && $fetchOptions['perPage'] > 0)
        {
            $limitOptions['limit'] = intval($fetchOptions['perPage']);
        }

        if (isset($fetchOptions['page']))
        {
            $page = $fetchOptions['page'];
            if ($page < 1)
            {
                $page = 1;
            }

            $limitOptions['offset'] = intval($page - 1) * $limitOptions['limit'];
        }

        return $limitOptions;
    }

	public function close()
	{
        $this->_driver->close();
	}

    protected function _cleanBind($bind)
    {
        if (!is_array($bind))
        {
            $bind = array($bind);
        }

        // Clean data
        foreach ($bind as $key => $val)
        {
            $bind[$key] = $this->escape($val);
        }

        return $bind;
    }

	protected function _loadDriver($driverName)
	{
		require_once('driver/' . $driverName . '.php');

		$driverClass = strtoupper($driverName);

		return new $driverClass();
	}
}